/** @format */

import { CODE_TYPES } from '../../constants'

export interface IDaoQuery {
  dao: IBaseDao
  query: IMongoQuery
}

/**
 * 并发更新
 * @param {接收数组或对象} daoqueryArr : [{dao: userdao, query:{_id:_id}}, {dao: activityprizedao, query: {userNick, status ...}}]
 * @param {*} fn
 * @param {*} times
 */
export const lockUpdate = async (daoqueryArr: IDaoQuery[], fn: () => {}, times = 5) => {
  if (typeof daoqueryArr !== 'object') {
    console.log(`lockUpdate 参数错误`)
    return false
  }
  if (!(daoqueryArr instanceof Array)) {
    daoqueryArr = [daoqueryArr]
  }
  let error = false
  for (let i = 0; i < daoqueryArr.length; i++) {
    let daoquery = daoqueryArr[i]
    if (!daoquery.dao || !daoquery.query) {
      error = true
      console.log(`daoquery`, daoquery)
      break
    }
  }
  if (error) {
    throw Error(`调用lockUpdate方法参数不符合规范`)
  }
  let time = 0
  console.log(`进入update并发处理次数`, times)
  let success = false
  try {
    while (time++ < times && !success) {
      let updateRes = await lock(daoqueryArr)
      console.log(`updateRes`, updateRes)
      // 若都锁定成功了，执行内部调用
      if (updateRes.every(v => v === 1)) {
        const ret = await fn()
        console.log(`完成调用，解锁操作执行--------------`)
        await unLock(daoqueryArr)
        success = true
        return ret
      } else {
        console.log(`进入waitFor了，需等待30ms`)
        await waitFor(30)
        success = false
      }
    }
  } catch (e) {
    console.log(e)
    await unLock(daoqueryArr)
    success = true
  }
  console.log(`daoqueryArr`, daoqueryArr)
  // 稍后重试
  if (!success) {
    await unLock(daoqueryArr)
    return CODE_TYPES.ERROR_UPDATE_RETRY
  }
  function waitFor(ms: number) {
    return new Promise(resolve => {
      setTimeout(resolve, ms)
    })
  }
}

async function unLock(daoqueryArr) {
  return await daoqueryArr.reduce(async (prev, daoquery) => {
    let ures = await daoquery.dao.update(daoquery.query, { $set: { lockStatus: 1 } })
    console.log(`更新lockStatus为1`, ures)
    prev.push(ures)
    return prev
  }, [])
}

async function lock(daoqueryArr) {
  return await daoqueryArr.reduce(async (prev, daoquery) => {
    console.log(`daoquery`, daoquery)
    let ures = await daoquery.dao.update(daoquery.query, { $set: { lockStatus: 2 } })
    console.log(`更新lockStatus为2`, ures)
    prev.push(ures)
    return prev
  }, [])
}

/**
 * 调用示例
 */
// 扣库存
// let res = await lockUpdate({dao: this.activityprizedao, query: {_id}}, async ()=> {
//   return await this.activityprizedao.update({_id}, {$set: {
//     useStock: useStock + 1,
//     updateTime: Date.now()
//   }});
// });
// console.log(res);
// if (!res) {
//   return CODE_TYPES.ERROR_UPDATE_RETRY;
// }
// return true;
